-
Notifications
You must be signed in to change notification settings - Fork 26
Add GeoDjango support #308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
c15694b
to
3020173
Compare
ec1c627
to
3f8b0fd
Compare
edbeeaa
to
de821e8
Compare
dc8bb43
to
a58fd36
Compare
c50f38c
to
50550c4
Compare
e50cf56
to
7f51e94
Compare
@@ -0,0 +1,59 @@ | |||
# Identical to test-python-atlas.yml except that gdal-bin is also installed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding both .github/workflows/test-python-geo.yml
and .github/workflows/test-python-atlas-geo.yml
might be redundant. (Are there any notable differences in GEO support on Atlas?) When the Atlas build ran with transactions, it was perhaps slightly more useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no differences between Geospatial querying and indexing done on Atlas vs. what is done on local atlas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant that test-python-geo.yml
uses supercharge/mongodb-github-action
(is this "standalone"?) and test-python-atlas-geo.yml
uses the Atlas VM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, looks good! Added a few questions, and would just like a test to confirm the 5 (of 6) data types can be inserted properly (even if un-queryable at the moment)
@@ -0,0 +1,59 @@ | |||
# Identical to test-python-atlas.yml except that gdal-bin is also installed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no differences between Geospatial querying and indexing done on Atlas vs. what is done on local atlas.
docs/source/ref/contrib/gis.rst
Outdated
|
||
- MongoDB doesn't support any spatial reference system identifiers | ||
(:attr:`BaseSpatialField.srid <django.contrib.gis.db.models.BaseSpatialField.srid>`) | ||
besides 4326 (WGS84) . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a link here?
besides 4326 (WGS84) . | |
besides `4326 (WGS84) <https://spatialreference.org/ref/epsg/4326/>` . |
#. Install the necessary :doc:`Geospatial libraries | ||
<django:ref/contrib/gis/install/geolibs>` (GEOS and GDAL). | ||
#. Add :mod:`django.contrib.gis` to :setting:`INSTALLED_APPS` in your settings. | ||
This is so that the ``gis`` templates can be located -- if not done, then | ||
features such as the geographic admin or KML sitemaps will not function properly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reservation to having it be an extension for us django-mongodb-backend[geos]
or something of that nature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The geospatial libraries aren't Python packages.
class GISTests(TestMixin, TransactionTestCase): | ||
@isolate_apps("schema_") | ||
def test_create_model(self): | ||
""" | ||
Spatial indexes for embedded GIS fields are created when the collections are | ||
created. | ||
""" | ||
from django.contrib.gis.db.models import PointField # noqa: PLC0415 | ||
|
||
class Place(EmbeddedModel): | ||
name = models.CharField(max_length=10) | ||
location = PointField() | ||
|
||
class Meta: | ||
app_label = "schema_" | ||
|
||
class Author(models.Model): | ||
birthplace = EmbeddedModelField(Place) | ||
|
||
class Meta: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a test that confirms field storage and database schema? For MongoDB
GeoJSON format still requires:
{ type: <GeoJSON Type>, ...}
as the data format. I see in the Adapter
does the work to ensure proper schema conversion, but I think it still helps to have a test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like a query with pymongo.find()
? Another thing to consider (if it assuages your concern) is that MongoDB raises an error (e.g. "can't extract geo keys") if a spatial index receives invalid data.
def __init__(self, obj, geography=False): | ||
""" | ||
Initialize on the spatial object. | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a link to the MongoDB GeoJSON Object types
in this docstring?
https://www.mongodb.com/docs/manual/reference/geojson/
7 out of 7 work (PointField, LineStringField, PolygonField, MultiPointField, MultiLineStringField, MultiPolygonField, GeometryCollectionField). It's tested in Django's test suite. Surprisingly, I had to add some tests for a few of the fields to our Django fork: Add tests for MultiPointField, MultiLineStringField, and GeometryCollectionFieldcommit 9dc4d37d7e8bb514922bd51c1a0940f5537e2c35
Author: Tim Graham <timograham@gmail.com>
Date: Fri Jul 25 15:41:50 2025 -0400
Add tests for MultiPointField, MultiLineStringField, and GeometryCollectionField
These should be contributed upstream to Django.
diff --git a/tests/gis_tests/geoapp/models.py b/tests/gis_tests/geoapp/models.py
index 2c13c827c6..c7acb653d3 100644
--- a/tests/gis_tests/geoapp/models.py
+++ b/tests/gis_tests/geoapp/models.py
@@ -102,3 +102,15 @@ class ManyPointModel(NamedModel):
point1 = models.PointField()
point2 = models.PointField()
point3 = models.PointField(srid=3857)
+
+
+class Points(models.Model):
+ geom = models.MultiPointField()
+
+
+class Lines(models.Model):
+ geom = models.MultiLineStringField()
+
+
+class GeometryCollections(models.Model):
+ geom = models.GeometryCollectionField()
diff --git a/tests/gis_tests/geoapp/tests.py b/tests/gis_tests/geoapp/tests.py
index f9abae129f..945d80a563 100644
--- a/tests/gis_tests/geoapp/tests.py
+++ b/tests/gis_tests/geoapp/tests.py
@@ -26,10 +26,13 @@ from .models import (
City,
Country,
Feature,
+ GeometryCollections,
+ Lines,
MinusOneSRID,
MultiFields,
NonConcreteModel,
PennsylvaniaCity,
+ Points,
State,
ThreeDimensionalFeature,
Track,
@@ -269,6 +272,47 @@ class GeoModelTest(TestCase):
self.assertEqual(feature.geom.srid, g.srid)
+# TODO: contribute these tests added to the MongoDB fork upstream to Django.
+class SaveLoadTests(TestCase):
+ def test_multi_line_string_field(self):
+ geom = MultiLineString(
+ LineString((0, 0), (1, 1), (5, 5)),
+ LineString((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)),
+ )
+ obj = Lines.objects.create(geom=geom)
+ obj.refresh_from_db()
+ self.assertEqual(obj.geom.tuple, geom.tuple)
+
+ def test_multi_line_string_with_linear_ring(self):
+ # LinearRings are transformed to LineString
+ geom = MultiLineString(
+ LineString((0, 0), (1, 1), (5, 5)),
+ LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0)),
+ )
+ obj = Lines.objects.create(geom=geom)
+ obj.refresh_from_db()
+ self.assertEqual(obj.geom.tuple, geom.tuple)
+ self.assertEqual(obj.geom[0].tuple, geom[0].tuple)
+ self.assertEqual(obj.geom[1].__class__.__name__, "LineString")
+ self.assertEqual(obj.geom[1].tuple, geom[1].tuple)
+
+ def test_multi_point_field(self):
+ geom = MultiPoint(Point(1, 1), Point(0, 0))
+ obj = Points.objects.create(geom=geom)
+ obj.refresh_from_db()
+ self.assertEqual(obj.geom, geom)
+
+ def test_geometry_collection_field(self):
+ geom = GeometryCollection(
+ Point(2, 2),
+ LineString((0, 0), (2, 2)),
+ Polygon(LinearRing((0, 0), (0, 5), (5, 5), (5, 0), (0, 0))),
+ )
+ obj = GeometryCollections.objects.create(geom=geom)
+ obj.refresh_from_db()
+ self.assertEqual(obj.geom, geom)
+
+
class GeoLookupTest(TestCase):
fixtures = ["initial"] |
No description provided.